﻿using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace OneWorks.Web.Common.ActionResults
{
    public class TreeGrid<T> : CustomResult<List<DynTree>>
    {
        private readonly IEnumerable<T> _nodes;
        private readonly List<DynTree> _treeNodes = new List<DynTree>();
        private readonly bool _isCollapse;
        private readonly Dictionary<string, NodeType> dictionary = new Dictionary<string, NodeType>();

        public TreeGrid(IEnumerable<T> nodes)
        {
            GetDictionary();
            _nodes = nodes ?? new List<T>();
            ConvertAll();
        }

        public TreeGrid(IEnumerable<T> nodes, bool IsCollapse = true)
        {
            GetDictionary();
            _nodes = nodes ?? new List<T>();
            _isCollapse = IsCollapse;
            ConvertAll();
        }

        public TreeGrid(IEnumerable<T> nodes, TreeMap<T> treeMap, bool IsCollapse = true)
        {
            dictionary = treeMap.GetDictionary();
            _nodes = nodes ?? new List<T>();
            _isCollapse = IsCollapse;
            ConvertAll();
        }

        private void GetDictionary()
        {
            foreach (PropertyInfo property in typeof(T).GetProperties())
            {
                var attrs = property.GetCustomAttributes(false);
                foreach (var tempAttr in attrs.OfType<TreeAttribute>())
                {
                    switch (tempAttr.NodeType)
                    {
                        case NodeType.Id:
                            dictionary.Add(property.Name, NodeType.Id);
                            break;
                        case NodeType.Parent:
                            dictionary.Add(property.Name, NodeType.Parent);
                            break;
                        case NodeType.Text:
                            dictionary.Add(property.Name, NodeType.Text);
                            break;
                        case NodeType.IconCls:
                            dictionary.Add(property.Name, NodeType.IconCls);
                            break;
                        case NodeType.Checked:
                            dictionary.Add(property.Name, NodeType.Checked);
                            break;
                        case NodeType.State:
                            dictionary.Add(property.Name, NodeType.State);
                            break;
                        case NodeType.Attribute:
                            dictionary.Add(property.Name, NodeType.Attribute);
                            break;
                    }
                }
            }
        }


        /// <summary>
        /// 将单个泛型转换具体操作实体
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private DynTree ConvertTreeEntity(T source)
        {
            DynTree treeEntity = new DynTree();
            PropertyInfo[] propertyInfos = source.GetType().GetProperties();
            Dictionary<string, object> attrDictionary = new Dictionary<string, object>();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (dictionary.ContainsKey(propertyInfo.Name))
                {
                    NodeType nodeType = dictionary[propertyInfo.Name];
                    switch (nodeType)
                    {
                        case NodeType.Id:
                            treeEntity.ID = propertyInfo.GetValue(source, null);
                            break;
                        case NodeType.Parent:
                            treeEntity.Parent = propertyInfo.GetValue(source, null);
                            break;
                        case NodeType.Text:
                            treeEntity.Text = (string)propertyInfo.GetValue(source, null);
                            break;
                        case NodeType.IconCls:
                            treeEntity.IconCls = (string)propertyInfo.GetValue(source, null);
                            break;
                        case NodeType.Checked:
                            treeEntity.Checked = (bool)propertyInfo.GetValue(source, null) ? "true" : "false";
                            break;
                        case NodeType.State:
                            treeEntity.Checked = (bool)propertyInfo.GetValue(source, null) ? "open" : "closed";
                            break;
                        case NodeType.Attribute:
                            attrDictionary.Add(propertyInfo.Name, propertyInfo.GetValue(source, null));
                            break;
                    }
                }
                treeEntity.SetPropertyValue(propertyInfo.Name, propertyInfo.GetValue(source, null));
            }
            treeEntity.Attributes = attrDictionary;
            return treeEntity;
        }

        /// <summary>
        /// 泛型集合转换具体操作实体
        /// </summary>
        private void ConvertAll()
        {
            foreach (T node in _nodes)
            {
                _treeNodes.Add(ConvertTreeEntity(node));
            }
        }

        /// <summary>
        /// 获取子集
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private List<DynTree> GetChilds(object id)
        {
            List<DynTree> entities = new List<DynTree>();
            var node = _treeNodes.Where(n => (n.Parent != null && n.Parent.Equals(id))).ToList();
            foreach (DynTree entity in node)
            {
                entity.Childrens = GetChilds(entity.ID);

                if (entity.Childrens.Any() && _isCollapse)
                {
                    entity.State = "closed";
                }

                if (string.IsNullOrEmpty(entity.IconCls))
                {
                    entity.IconCls = "icon-shape_move_backwards";
                }
                entities.Add(entity);
            }
            return entities;
        }

        public override List<DynTree> GetObject()
        {
            if (_treeNodes.Any(t => t.Parent == null))
            {
                List<DynTree> rooTrees = _treeNodes.Where(t => t.Parent == null).ToList();
                foreach (DynTree rooTree in rooTrees)
                {
                    rooTree.Childrens = GetChilds(rooTree.ID);
                }
                return rooTrees;
            }
            else
            {
                List<DynTree> rooTrees = new List<DynTree>();
                foreach (DynTree treeNode in _treeNodes)
                {
                    var any = _treeNodes.Any(t => t.ID.Equals(treeNode.Parent));
                    if (!any)
                    {
                        treeNode.Childrens = GetChilds(treeNode.ID);
                        rooTrees.Add(treeNode);
                    }
                }
                return rooTrees;
            }
        }
    }
}
